///////////////////////////////////////////////////////////////////////////////
// File:        ByteBuffer.hpp
// Author:      671643387@qq.com
// Description:
///////////////////////////////////////////////////////////////////////////////

#ifndef MONKEY_COMMON_BYTEBUFFER_HPP_
#define MONKEY_COMMON_BYTEBUFFER_HPP_

#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif

#include <memory.h>
#include <cassert>
#include <cstdint>
#include <vector>
#include "common/Config.hpp"

namespace monkey
{
    namespace common
    {
        class ByteBufferException
        {
        public:
            ByteBufferException(bool _add, size_t _pos, size_t _esize, size_t _size)
                : add(_add), pos(_pos), esize(_esize), size(_size)
            {
                PrintPosError();
            }

            void PrintPosError() const;
        private:
            bool add;
            size_t pos;
            size_t esize;
            size_t size;
        };

        class ByteBuffer
        {
        public:
            typedef ByteBuffer          Self;
            typedef std::vector<char>   ByteArray;

        public:
            ByteBuffer(size_t size)
                : rpos_(0)
                , wpos_(0)
            {
                storage_.reserve(size);
            }

            ~ByteBuffer(void)
            {
            }

        public:
            ///////////////////////////////////////////////////////////////////

            ByteArray::size_type Size(void)
            {
                return storage_.size();
            }

            const char* Contents(void) const
            {
                return &storage_[0];
            }

            ///////////////////////////////////////////////////////////////////

            void Append(const char* src, size_t length)
            {
                if (length == 0)
                    return;

                assert(Size() < BYTE_BUFFER_MAX_SIZE);
                if (storage_.size(), (wpos_ + length))
                    storage_.reserve(wpos_ + length);
                memcpy(&storage_[wpos_], src, length);
                wpos_ += length;
            }

            template<typename T>
            void Append(T& x)
            {
                Append((const char*)&x, sizeof(T));
            }

            ///////////////////////////////////////////////////////////////////

            Self& operator<<(uint8_t& x)
            {
                Append<uint8_t>(x);
                return *this;
            }

            Self& operator<<(uint16_t& x)
            {
                Append<uint16_t>(x);
                return *this;
            }

            Self& operator<<(uint32_t& x)
            {
                Append<uint32_t>(x);
                return *this;
            }

            Self& operator<<(uint64_t& x)
            {
                Append<uint64_t>(x);
                return *this;
            }

            Self& operator<<(float& x)
            {
                Append<float>(x);
                return *this;
            }

            Self& operator<<(double& x)
            {
                Append<double>(x);
                return *this;
            }

            ///////////////////////////////////////////////////////////////////

        private:
            ByteArray storage_;
            size_t rpos_;
            size_t wpos_;
        };
    }
}

#endif /* MONKEY_COMMON_BYTEBUFFER_HPP_ */
